/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "semphr.h"
#include "gpio.h"
#include "rtc.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_date.h"
#include "bsp_weather.h"
#include "bsp_esp8266.h"
#include "bsp_esp8266_test.h"
#include "jsmn.h" // json process
#include "oled.h"
#include "core_delay.h"
#include "bmp.h" // desk picture

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
typedef enum {
    STATE_NORMAL,
		STATE_SET_YEAR,
    STATE_SET_MONTH,
		STATE_SET_DAY,
    STATE_SET_HOUR,
    STATE_SET_MINUTE,
		STATE_SET_SECOND,
		STATE_IFCONFIRM,
    STATE_CONFIRM,
		STATE_CANCEL
} TimeState;

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/// display time used ///
#define CLEAR_PREVIOUS_TIME 1
#define DONOT_CLEAR_PREVIOUS_TIME 0

#define USART_REC_LEN 200
#define QUEUE_LENGTH 1
#define Weather_ITEM_SIZE sizeof( struct weatherStruct )
#define Time_ITEM_SIZE sizeof( struct timeStruct )
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
__IO uint32_t TimeDisplay = 0;
__IO TimeState SetTimeState = STATE_NORMAL;

uint8_t aRxBuffer1;											//usart1 receive buffer
uint8_t USART1_RX_BUF[USART_REC_LEN];		//usart1 receive buffers
uint16_t USART1_RX_STA;									//usart1 receive buffer counter
uint8_t	Res;														//usart1 receive temp variable
uint8_t aRxBuffer3;											//usart3 receive buffer
uint8_t ucCh; 													//usart3 receive temp variable

uint8_t set_alarm = 0;									//whether enter set alarm mode

struct timeStruct structTimeData;				//time structure
struct timeStruct t_structTimeData;			//latest time data

char stringWeatherData[512];						//weather string
int stringWeatherData_index = 0;				//weather string index
jsmn_parser jsonWeatherData;						//weather data in json format

struct weatherStruct structWeatherData; 	//weather structure
struct weatherStruct t_structWeatherData; //latest weather data
///////   queue time used	 ///////
StaticQueue_t xTimeQueue;
uint8_t TimeQueueStorage[ QUEUE_LENGTH * Time_ITEM_SIZE ];
QueueHandle_t timeQueue;
///////   queue weather used	 ///////
StaticQueue_t xWeatherQueue;
uint8_t WeatherQueueStorage[ QUEUE_LENGTH * Weather_ITEM_SIZE ];
QueueHandle_t weatherQueue;
/////// mutex oled used for i2c ///////
StaticSemaphore_t i2cMutex;
SemaphoreHandle_t i2cMutexHandle;
/////// semaphore weather used( usart3 finished receiving ) ///////
StaticSemaphore_t weatherRevFinishedSemaphore;
SemaphoreHandle_t weatherRevFinishedSemaphoreHandle;

extern uint8_t SetTimeCnt;							 // set time counter
extern uint8_t ucTcpClosedFlag;					 // tcp connected flag 
extern struct STRUCT_USARTx_Fram strEsp8266_Fram_Record; //Esp8266 structure for receiving data

/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
void Task_Init(void *argument);
void Task_Init_ESP8266(void *argument);
void Task_Time(void *argument);
void Task_TimeDisplay(void *argument);
void Task_Weather(void *argument);
void Task_WeatherDisplay(void *argument);

void parse_weather_data(const char *json);
void Weather_Display(struct weatherStruct);
/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */


/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
	i2cMutexHandle = xSemaphoreCreateMutexStatic( &i2cMutex );
	
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
	weatherRevFinishedSemaphoreHandle =  xSemaphoreCreateBinaryStatic( &weatherRevFinishedSemaphore );
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
	timeQueue = xQueueCreateStatic( QUEUE_LENGTH, Time_ITEM_SIZE, TimeQueueStorage, &xTimeQueue );
	xQueueReset(timeQueue);
	weatherQueue = xQueueCreateStatic( QUEUE_LENGTH, Weather_ITEM_SIZE, WeatherQueueStorage, &xWeatherQueue );
	xQueueReset(weatherQueue);
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */
  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
	//xTaskCreate( InitTask, "InitTask", 128 * 4, NULL, configMAX_PRIORITIES, NULL );
	OLED_Clear();
	xTaskCreate( Task_Init, "Init", 128 * 4, NULL, configMAX_PRIORITIES, NULL );
	xTaskCreate( Task_Init_ESP8266, "InitESP", 128 * 4, NULL, configMAX_PRIORITIES-2, NULL );
	xTaskCreate( Task_Time, "Time", 128 * 20, NULL, configMAX_PRIORITIES-2, NULL );
	xTaskCreate( Task_TimeDisplay, "TimeDisplay", 128 * 4, NULL, configMAX_PRIORITIES-2, NULL );
//	xTaskCreate( Task_Weather, "Weather", 128 * 20, NULL, configMAX_PRIORITIES-2 , NULL );
//	xTaskCreate( Task_WeatherDisplay, "WeatherDisplay", 128 * 4, NULL, configMAX_PRIORITIES-2 , NULL );
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

///////// tasks /////////
/// Init a part of peripheral ///
void Task_Init(void *argument){
	while(1){
		/* load desk picture and clear time part */
		OLED_DrawBMP(0,0,128,8,BMP2);
		for(int i = time_y; i <= weather_y; i++){
			OLED_Clearrow(i);
		}
		/* Init USART1 interupt for debug */
		HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer1, 1);
		printf("USART1 Interupt init finished!\n");
		
//		RTC_AlarmTypeDef sAlarm = {0};
//		sAlarm.AlarmTime.Hours = 23;
//		sAlarm.AlarmTime.Minutes = 59;
//		sAlarm.AlarmTime.Seconds = 50;
//		sAlarm.Alarm = RTC_ALARM_A; // 配置闹钟A
//		HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
		
		vTaskDelete(NULL);
	}
}
/// Init ESP8266 and peripheral it uesd ///
void Task_Init_ESP8266(void *argument){
		/* Init USART3 interupt for esp8266 */
		HAL_UART_Receive_IT(&huart3, (uint8_t *)&aRxBuffer3, 1);
		printf("USART3 Interupt init finished!\n");
		
		/* Init esp8266 wifi module */
		CPU_TS_TmrInit(); //Init DWT counter for delay                                               
		printf("ESP8266_Init finishing!\n");
		ESP8266_Init();
		printf("ESP8266_Init finished!\n");
		
		printf("ESP8266 configing!\n");
		ESP8266_StaTcpClient_Unvarnish_ConfigTest(); 
		printf("ESP8266 config finished!\n");
	
		xTaskCreate( Task_Weather, "Weather", 128 * 20, NULL, configMAX_PRIORITIES-2 , NULL );
		xTaskCreate( Task_WeatherDisplay, "WeatherDisplay", 128 * 4, NULL, configMAX_PRIORITIES-2 , NULL );
	
		vTaskDelete(NULL);
}
/// Read or Set time(alarm) ///
void Task_Time(void *argument){
	while(1){
		/* whether user tap the set time key(key1) */
		if(SetTimeState != STATE_NORMAL){
			/* take i2c semaphore */
			xSemaphoreTake(i2cMutexHandle, portMAX_DELAY);
			struct timeStruct SaveTimeData;
			struct timeStruct SetTimeData;
			/* save RTC data */
			SaveTimeData = structTimeData;
			SetTimeData = structTimeData;
			/* clear time page and weather page */
			Time_Display(&SaveTimeData, CLEAR_PREVIOUS_TIME, SetTimeState);
			OLED_Clearrow(set_y);
			/* diplay set time page, receive count and change SetTimeData */
			while(SetTimeState != STATE_NORMAL){
				switch(SetTimeState){
					case STATE_SET_YEAR:
						SetTimeData.date.Year += SetTimeCnt;
						SetTimeCnt = 0;
						SetedDisplay(3);
						break;
					case STATE_SET_MONTH:
						SetTimeData.date.Month = (SetTimeData.date.Month + SetTimeCnt) % 13;
						SetTimeCnt = 0;
						break;
					case STATE_SET_DAY:
						SetTimeData.date.Date = (SetTimeData.date.Date + SetTimeCnt) % 31;
						SetTimeCnt = 0;
						break;
					case STATE_SET_HOUR:
						SetTimeData.time.Hours = (SetTimeData.time.Hours + SetTimeCnt) % 24;
						SetTimeCnt = 0;
						break;
					case STATE_SET_MINUTE:
						SetTimeData.time.Minutes = (SetTimeData.time.Minutes + SetTimeCnt) % 60;
						SetTimeCnt = 0;
						break;
					case STATE_SET_SECOND:
						SetTimeData.time.Seconds = (SetTimeData.time.Seconds + SetTimeCnt) % 60;
						SetTimeCnt = 0;
						break;
					case STATE_IFCONFIRM:
						/* display ifconfirm page */
						SetedDisplay(2);
						break;
					case STATE_CONFIRM:
						SetTimeCnt = 0;
						/* display seted page */
						SetedDisplay(1);
						break;
					case STATE_CANCEL:
						SetTimeData = SaveTimeData;
						SetTimeCnt = 0;
						/* display cancel page */
						SetedDisplay(0);
						break;
					default:
						break;
				}
				Time_Display(&SetTimeData, DONOT_CLEAR_PREVIOUS_TIME, SetTimeState);
			}
			/* write data to RTC */
			/* check whether is set time mode or set alarm mode */
			if(!set_alarm){
				HAL_RTC_SetTime(&hrtc, &SetTimeData.time, RTC_FORMAT_BIN);
				HAL_RTC_SetDate(&hrtc, &SetTimeData.date, RTC_FORMAT_BIN);
				/* write data to queue */
				xQueueSend(timeQueue, &SetTimeData, 0);
			}
			else{
				RTC_AlarmTypeDef sAlarm = {0};
				sAlarm.AlarmTime.Hours = SetTimeData.time.Hours;
				sAlarm.AlarmTime.Minutes = SetTimeData.time.Minutes;
				sAlarm.AlarmTime.Seconds = SetTimeData.time.Seconds;
				sAlarm.Alarm = RTC_ALARM_A; // config alarm A
				HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN);
				set_alarm = 0;
			}
			/* display weather again */
			OLED_Clearrow(set_y);
			Weather_Display(t_structWeatherData); 
			/* give i2c semaphore */
			xSemaphoreGive( i2cMutexHandle );
		}
		/* read data from RTC */
		if (TimeDisplay/* && res == pdTRUE*/)
		{
			structTimeData = Time_Get();
			/* write data to queue */
			xQueueSend(timeQueue, &structTimeData, 0);
		}
	}
}
/// Display time ///
void Task_TimeDisplay(void *argument){
	while(1){
		/* read queue with maxdelay */
		xQueueReceive( timeQueue, &t_structTimeData, portMAX_DELAY);
		/* take i2c semaphore */
		BaseType_t res = xSemaphoreTake(i2cMutexHandle, portMAX_DELAY);
		/* Display current time */
		Time_Display(&t_structTimeData, DONOT_CLEAR_PREVIOUS_TIME, SetTimeState);
		TimeDisplay = 0;
		/* give i2c semaphore */
		res = xSemaphoreGive( i2cMutexHandle );
	}
}
/// Get weather data ///
void Task_Weather(void *argument){
	while(1){
		/* send request to server */
		vTaskDelay(5000);
		macESP8266_Usart("GET https://%s/v3/weather/now.json?key=%s&location=%s&language=en\r\n", 
									macUser_ESP8266_TcpServer_IP, macUser_ESP8266_TcpServer_key, macUser_ESP8266_TcpServer_city);  
		/* take signal (usart3 receive finished)*/
		xSemaphoreTake(weatherRevFinishedSemaphoreHandle, portMAX_DELAY);
		/* read data from usart3 */
		ESP8266_RecvData();
		char *weather_json_start = strchr(stringWeatherData, '{'); // find json data
    if (weather_json_start == NULL) {
        printf("No JSON data found.\n");
    }
		else{
			/* parse data and write to queue */
			parse_weather_data(weather_json_start);
		}
	}
}
/// Display weather data ///
void Task_WeatherDisplay(void *argument){
	while(1){
		/* read queue */
		xQueueReceive( weatherQueue, &t_structWeatherData, portMAX_DELAY);
		/* take i2c semaphore */
		xSemaphoreTake(i2cMutexHandle, portMAX_DELAY);
		/* display weather */
		Weather_Display(t_structWeatherData); 
		/* give i2c semaphore */
		xSemaphoreGive( i2cMutexHandle );
	}
}
/// parse json data and write to queue ///
void parse_weather_data(const char *json) {
	int w_flag = 0; // whether found weather
	int t_flag = 0; // whether found temperature
	jsmntok_t tokens[128]; // 32tokens
	jsmn_init(&jsonWeatherData);
	int ret = jsmn_parse(&jsonWeatherData, json, strlen(json), tokens, sizeof(tokens) / sizeof(tokens[0]));
	if (ret < 0) {
			/* no json data */
			return;
	}
	// parse JSON tokens
	for (int i = 1; i < ret; i++) {
			if (strncmp("text", json + tokens[i].start, tokens[i].end - tokens[i].start) == 0 && !w_flag) {
				strncpy(structWeatherData.weather, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start);
				structWeatherData.weather[tokens[i + 1].end - tokens[i + 1].start] = '\0';
				printf("weather: %s\n", structWeatherData.weather);
				w_flag = 1;
			}
			if (strncmp("temperature", json + tokens[i].start, tokens[i].end - tokens[i].start) == 0 && !t_flag) {
				strncpy(structWeatherData.temperature, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start);
				structWeatherData.temperature[tokens[i + 1].end - tokens[i + 1].start] = '\0';
				printf("temperature: %s\n", structWeatherData.temperature);
				t_flag = 1;
			}
	}
	/* write to queue */
	 xQueueSend(weatherQueue, &structWeatherData, 0);
}
/// ALL USART interupt call back function ///
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart ->Instance == USART1)
    {
				if((USART1_RX_STA&0x8000)==0)
				{
					if(Res==0x0D)
					{
						USART1_RX_STA|=0x8000;
						HAL_UART_Receive_IT(&huart1, &Res, 1);
					}
					else
					{
						USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ;
						USART1_RX_STA++;
						if(USART1_RX_STA>(USART_REC_LEN-1))
							USART1_RX_STA=0;
					}		 
				}
				HAL_UART_Receive_IT(huart,&Res,1);
				printf("%c", Res);
    }
		else if(huart ->Instance == USART3){
			//printf("enter usart3 interupt\n");
			if(ucCh==0x0D) // finish
			{
				strEsp8266_Fram_Record .InfBit .FramFinishFlag = 1;
				ucTcpClosedFlag = strstr ( strEsp8266_Fram_Record .Data_RX_BUF, "CLOSED" ) ? 1 : 0;
				//printf("FramFinishFlag: %d ucTcpClosedFlag is %d\n", strEsp8266_Fram_Record .InfBit .FramFinishFlag, ucTcpClosedFlag);
				ucCh = 0;
				HAL_UART_Receive_IT(&huart3, &ucCh, 1);
				BaseType_t woken;
				xSemaphoreGiveFromISR( weatherRevFinishedSemaphoreHandle, &woken);
			}
			else
			{
				if ( strEsp8266_Fram_Record .InfBit .FramLength < ( RX_BUF_MAX_LEN - 1 ) )                       //Ԥ��1���ֽ�д������
				 strEsp8266_Fram_Record .Data_RX_BUF [ strEsp8266_Fram_Record .InfBit .FramLength ++ ]  = ucCh;
				HAL_UART_Receive_IT(&huart3, &ucCh, 1);
			}	
		}
}
/// RTC alarm call back function ///
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
		printf("enter alarm interupt\n");
}

/* USER CODE END Application */

